﻿using MyDelegateDemo.Linq;
using MyDelegateDemo.MyObserver;
using static MyDelegateDemo.Student;

namespace MyDelegateDemo
{
    internal class Program
    {
        static void Main(string[] args)
        {
            try
            {

                //一. 什么是委托?
                //1.形如一个方法,有修饰符,带有关键字:delegate, 有返回值的声明, 有参数的声明----委托了;和方法不一样, 就是没有方法体的部分;
                //2.委托的本质究竟是什么? 底层是什么, 原理是什么?---工具--IL-Spay--反编译工具
                //3.委托的本质是其实是一个Class 类, 继承自一个[System.Runtime]System.MulticastDelegate 特殊类, 委托是一个类, 就可以把委托当做一个类来使用?  
                //4. 实例化委托, 可以执行委托 Invoke方法--执行委托--其实会把实例化委托的时候, 给定的方法给指定掉;  执行委托还是执行方法;

                //5. 委托是一个类----得到类的实例, 就可以把实例当做参数来传递; 委托中可以可以执向某个方法, 如果把委托传递到特定的地方, 执行委托---可以把带过去的方法给执行掉;
                //6. 委托的作用: 可以把方法(行为)当做参数来传递;  
                //7. 实例化 , 注意: 一定要执向的方法必须和委托的参数和返回值完全吻合;


                #region 2023
                {
                    //new CustomDelegate().Show();
                }
                #endregion

                //二. 委托到底有什么价值呢?

                //案例: 招呼~~
                //如果有不同的类型的打招呼的方式, 来自于不同的地方人;
                //武汉人---吃了么
                //广东人---雷猴~
                //北京人---你好~

                //两种方案:
                //方案一: 可以为每个地方的人各自定义一个方法;
                //优势:
                //1. 为新业务定义新方法---保持不修改历史业务逻辑--设计原则--开闭原则--保持代码的稳定性;


                //方案二:  可以在SayHi的内部,做分支判断, 是哪个地方的人, 就根据不同的地方的到招呼方式, 进行打招呼~
                //劣势:
                //1. 修改了历史代码--委托了开闭原则--肯定会导致代码不稳定

                //你们认为,哪个方案好?
                //新问题:
                //需求1: 如果我希望增加一个地方的人:
                //方案一: 优势:增加方法, 不影响其他的方法稳定;--代码更加稳定;
                //方案二: 劣势:增加分支判断, 修改历史代码---导致代码不稳定;

                //需求2: 如果我希望增加公共的业务逻辑---打招呼---招招手~
                //方案一:  劣势: 出现了大量的重复代码~
                //方案二:  优势: 没有重复代码了~

                //需求不一样:  各有优势和劣势~  方案一/二, 都不是完美的~

                //三. 有没有完美方案呢, 当然有~~
                //方案二.  定义枚举参数--为了选择不同的执行逻辑, 选择逻辑的. 那能不能直接传递逻辑呢?  什么是逻辑?  其实就是方法, 可以把方法传递过来呢?
                //如果要传递方法---怎么办?  委托呗;

                //四. 委托使用建议;
                //1. 如果发现你的代码职责不单一,耦合太重; 考虑使用委托
                //2. 如果发现你的代码,有很多重复代码, 考虑使用委托来优化~

                {
                    //Student student = new Student();
                    ////student.Study();


                    ////SayHiMehtod hiMehtod1 = student.SayHiWuHan;
                    ////student.SayHiPerfact(hiMehtod1);

                    ////SayHiMehtod hiMehtod2 =  student.SayHiGuangDong;
                    ////student.SayHiPerfact(hiMehtod2);

                    ////SayHiMehtod hiMehtod3 = student.SayHiBeiJing;
                    ////student.SayHiPerfact(hiMehtod3);

                    ////SayHiMehtod hiMehtod4 = student.SayHiShangHai;
                    ////student.SayHiPerfact(hiMehtod4);

                    //Action hiMehtod1 = student.SayHiWuHan;
                    //student.SayHiPerfact(hiMehtod1);

                    //Action hiMehtod2 = student.SayHiGuangDong;
                    //student.SayHiPerfact(hiMehtod2);

                    //Action hiMehtod3 = student.SayHiBeiJing;
                    //student.SayHiPerfact(hiMehtod3);

                    //Action hiMehtod4 = student.SayHiShangHai;
                    //student.SayHiPerfact(hiMehtod4); 
                }

                //五. 未来是使用委托,建议大家可以直接使用Action/Func

                //Action<int>: 没有返回值的委托 参数个数: 从0到16
                //Func<int>  : 有返回值: 参数个数:从0到16
                //系统提供的委托;

                //责任链模式, 或者是 建造者模式;



                //六. 委托可以包装一个方法, 委托也可以包装一个委托;----俄罗斯套---.NET Core 中间件的核心----充分的使用委托;  委托包委托;

                //需求: 如果我希望能够在Show前后动态的增加一些逻辑呢?


                {
                    MyDelegateRichardExtend myDelegateRichardExtend = new MyDelegateRichardExtend();

                    //如果希望在Show方法前面增加点业务逻辑
                    //增加一些日志输出

                    Func<Action, Action> actionlog1 = p => {

                        Console.WriteLine("输入日志: Befor001");
                        return p;
                    };
                    Func<Action, Action> actionlog2 = p => {

                        Console.WriteLine("输入日志: Befor002");
                        return p;
                    };
                    Func<Action, Action> actionlog3 = p => {

                        Console.WriteLine("输入日志: Befor003");
                        return p;
                    }; ;

                    Func<Action, Action> actionlog4 = p => {

                        Console.WriteLine("输入日志: Befor004");
                        return p;
                    }; ;

                    Func<Action, Action> actionlog5 = p => {

                        Console.WriteLine("输入日志: Befor005");
                        return p;
                    }; ;

                    myDelegateRichardExtend.actionList.Add(actionlog1);
                    myDelegateRichardExtend.actionList.Add(actionlog2);
                    myDelegateRichardExtend.actionList.Add(actionlog3);
                    myDelegateRichardExtend.actionList.Add(actionlog4);
                    myDelegateRichardExtend.actionList.Add(actionlog5);


                    myDelegateRichardExtend.Show();

                }

            }
            catch (Exception ex)
            {
                throw;
            }
        }
    }
}